package ru.kreda.webapp.client.logic;

import java.util.ArrayList;
import java.util.List;

import ru.kreda.webapp.client.place.AbstractPlace;
import ru.kreda.webapp.shared.AppException;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.place.shared.Place;

/**
 * Базовая реализация {@link Activity}, хранящая {@link Place}. Также
 * осуществляет дерегистрацию зарегистрированных обработчиков.
 */
public abstract class AbstractActivityWithPlace<T extends AbstractPlace> extends AbstractActivity {
	private T place;
	private List<HandlerRegistration> handlers = new ArrayList<HandlerRegistration>();

	/**
	 * Возвращает соответствующий {@link Place}, не может быть <code>null</code>
	 */
	public T getPlace() {
		if (place == null) {
			throw new AppException("Ошибка навигации (place == null)");
		}
		return place;
	}

	/**
	 * Устанавливает соответствующий {@link Place}. Вызывается перед
	 * {@link Activity#start(com.google.gwt.user.client.ui.AcceptsOneWidget, com.google.gwt.event.shared.EventBus)}
	 */
	public AbstractActivityWithPlace<T> withPlace(T place) {
		this.place = place;
		return this;
	}

	@Override
	public void onStop() {
		for (HandlerRegistration handlerRegistration : handlers) {
			handlerRegistration.removeHandler();
		}
		super.onStop();
	}

	/**
	 * Добавляет обработчик UI в список обработчиков, дерегистрируемых при
	 * остановке activity. Сюда не нужно добавлять обработчики, подключаемые к
	 * event bus.
	 */
	protected void addHandler(HandlerRegistration handlerRegistration) {
		if (handlerRegistration != null) {
			handlers.add(handlerRegistration);
		}
	}

	/**
	 * Подходит ли данный activity для нового place. В случае <code>true</code>
	 * данный activity будет использоваться для другого place. В случае
	 * <code>false</code> данный activity будет остановлен, а запущен будет
	 * новый.
	 */
	protected boolean suitForPlace(T newPlace) {
		return getPlace().equals(newPlace);
	}

	@SuppressWarnings({ "unchecked" })
	@Override
	public boolean equals(Object obj) {
		if (getClass() == obj.getClass()) {
			T newPlace = ((AbstractActivityWithPlace<T>) obj).getPlace();
			// TODO ?
			/*
			 * if (newPlace.getClass().isAssignableFrom(place.getClass())) {
			 * return newPlace.equals(place); } if
			 * (place.getClass().isAssignableFrom(newPlace.getClass())) { return
			 * place.equals(newPlace); }
			 */
			return suitForPlace(newPlace);
		}
		return false;
	}

}
